// ============================================
// internal/service/network_service.go
// ============================================

package service

import (
	"context"
	"fmt"
	"time"

	"github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
	"libvirt.org/go/libvirtxml"

	"virt-manager-go/internal/domain"
)

type networkService struct {
	connMgr domain.ConnectionManager
	logger  *logrus.Logger
}

func NewNetworkService(connMgr domain.ConnectionManager, logger *logrus.Logger) domain.NetworkService {
	return &networkService{
		connMgr: connMgr,
		logger:  logger,
	}
}

// ListNetworks 列出所有网络
func (s *networkService) ListNetworks(ctx context.Context, connID string) ([]*domain.NetworkInfo, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	networks, err := conn.ListAllNetworks(libvirt.CONNECT_LIST_NETWORKS_ACTIVE | libvirt.CONNECT_LIST_NETWORKS_INACTIVE)
	if err != nil {
		return nil, fmt.Errorf("failed to list networks: %w", err)
	}

	networkInfos := make([]*domain.NetworkInfo, 0, len(networks))
	for _, net := range networks {
		netInfo, err := s.networkToInfo(&net)
		net.Free()
		if err != nil {
			s.logger.WithError(err).Warn("Failed to convert network to info")
			continue
		}
		networkInfos = append(networkInfos, netInfo)
	}

	return networkInfos, nil
}

// GetNetwork 获取网络信息
func (s *networkService) GetNetwork(ctx context.Context, connID, networkName string) (*domain.NetworkInfo, error) {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return nil, err
	}
	defer net.Free()

	return s.networkToInfo(net)
}

// CreateNetwork 创建虚拟网络
func (s *networkService) CreateNetwork(ctx context.Context, connID string, config *domain.NetworkConfig) (*domain.NetworkInfo, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"network":    config.Name,
	}).Info("Creating virtual network")

	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	// 构建网络 XML
	xmlData, err := s.buildNetworkXML(config)
	if err != nil {
		return nil, fmt.Errorf("failed to build network XML: %w", err)
	}

	s.logger.WithField("xml", xmlData).Debug("Generated network XML")

	// 定义网络
	net, err := conn.NetworkDefineXML(xmlData)
	if err != nil {
		return nil, fmt.Errorf("failed to define network: %w", err)
	}
	defer net.Free()

	// 启动网络
	if err := net.Create(); err != nil {
		return nil, fmt.Errorf("failed to start network: %w", err)
	}

	// 设置自动启动
	if config.Autostart {
		if err := net.SetAutostart(true); err != nil {
			s.logger.WithError(err).Warn("Failed to set autostart")
		}
	}

	s.logger.WithField("network", config.Name).Info("Virtual network created successfully")

	return s.networkToInfo(net)
}

// DeleteNetwork 删除虚拟网络
func (s *networkService) DeleteNetwork(ctx context.Context, connID, networkName string) error {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return err
	}
	defer net.Free()

	// 检查是否活跃
	active, err := net.IsActive()
	if err != nil {
		return fmt.Errorf("failed to check network state: %w", err)
	}

	// 如果活跃，先停止
	if active {
		if err := net.Destroy(); err != nil {
			return fmt.Errorf("failed to stop network: %w", err)
		}
	}

	// 取消定义
	if err := net.Undefine(); err != nil {
		return fmt.Errorf("failed to undefine network: %w", err)
	}

	s.logger.WithField("network", networkName).Info("Virtual network deleted")
	return nil
}

// StartNetwork 启动网络
func (s *networkService) StartNetwork(ctx context.Context, connID, networkName string) error {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return err
	}
	defer net.Free()

	if err := net.Create(); err != nil {
		return fmt.Errorf("failed to start network: %w", err)
	}

	s.logger.WithField("network", networkName).Info("Virtual network started")
	return nil
}

// StopNetwork 停止网络
func (s *networkService) StopNetwork(ctx context.Context, connID, networkName string) error {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return err
	}
	defer net.Free()

	if err := net.Destroy(); err != nil {
		return fmt.Errorf("failed to stop network: %w", err)
	}

	s.logger.WithField("network", networkName).Info("Virtual network stopped")
	return nil
}

// SetAutostart 设置自动启动
func (s *networkService) SetAutostart(ctx context.Context, connID, networkName string, autostart bool) error {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return err
	}
	defer net.Free()

	if err := net.SetAutostart(autostart); err != nil {
		return fmt.Errorf("failed to set autostart: %w", err)
	}

	return nil
}

// GetDHCPLeases 获取 DHCP 租约
func (s *networkService) GetDHCPLeases(ctx context.Context, connID, networkName string) ([]*domain.DHCPLease, error) {
	net, err := s.getNetwork(connID, networkName)
	if err != nil {
		return nil, err
	}
	defer net.Free()

	leases, err := net.GetDHCPLeases()
	if err != nil {
		return nil, fmt.Errorf("failed to get DHCP leases: %w", err)
	}

	dhcpLeases := make([]*domain.DHCPLease, 0, len(leases))
	for _, lease := range leases {
		dhcpLeases = append(dhcpLeases, &domain.DHCPLease{
			IPAddress:  lease.IPaddr,
			MACAddress: lease.Mac,
			Hostname:   lease.Hostname,
			ExpiryTime: lease.ExpiryTime,
			Type:       fmt.Sprintf("ipv%d", lease.Type),
		})
	}

	return dhcpLeases, nil
}

// === 辅助方法 ===

func (s *networkService) getNetwork(connID, networkName string) (*libvirt.Network, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	net, err := conn.LookupNetworkByName(networkName)
	if err != nil {
		return nil, fmt.Errorf("network not found: %w", err)
	}

	return net, nil
}

func (s *networkService) networkToInfo(net *libvirt.Network) (*domain.NetworkInfo, error) {
	name, err := net.GetName()
	if err != nil {
		return nil, err
	}

	uuid, err := net.GetUUIDString()
	if err != nil {
		return nil, err
	}

	active, _ := net.IsActive()
	persistent, _ := net.IsPersistent()
	autostart, _ := net.GetAutostart()

	// 解析 XML 获取详细信息
	xmlData, err := net.GetXMLDesc(0)
	if err != nil {
		return nil, err
	}

	netConfig := &libvirtxml.Network{}
	if err := netConfig.Unmarshal(xmlData); err != nil {
		return nil, err
	}

	netInfo := &domain.NetworkInfo{
		Name:       name,
		UUID:       uuid,
		Active:     active,
		Persistent: persistent,
		Autostart:  autostart,
		CreatedAt:  time.Now(),
	}

	if netConfig.Bridge != nil {
		netInfo.Bridge = netConfig.Bridge.Name
	}

	if netConfig.Forward != nil {
		netInfo.Forward = domain.ForwardMode(netConfig.Forward.Mode)
	}

	if netConfig.Domain != nil {
		netInfo.Domain = netConfig.Domain.Name
	}

	// 解析 IP 配置
	for _, ip := range netConfig.IPs {
		netIP := domain.NetworkIP{
			Address: ip.Address,
			Netmask: ip.Netmask,
		}

		if ip.DHCP != nil {
			netIP.DHCP = &domain.NetworkDHCP{
				Start: ip.DHCP.Ranges[0].Start,
				End:   ip.DHCP.Ranges[0].End,
			}

			for _, host := range ip.DHCP.Hosts {
				netIP.DHCP.Hosts = append(netIP.DHCP.Hosts, domain.DHCPHost{
					MAC:  host.MAC,
					Name: host.Name,
					IP:   host.IP,
				})
			}
		}

		netInfo.IP = append(netInfo.IP, netIP)
	}

	return netInfo, nil
}

func (s *networkService) buildNetworkXML(config *domain.NetworkConfig) (string, error) {
	netConfig := &libvirtxml.Network{
		Name: config.Name,
	}

	// 设置桥接
	if config.Bridge != "" {
		netConfig.Bridge = &libvirtxml.NetworkBridge{
			Name: config.Bridge,
			STP:  "on",
		}
	}

	// 设置转发模式
	if config.Forward != "" {
		netConfig.Forward = &libvirtxml.NetworkForward{
			Mode: string(config.Forward),
		}
	}

	// 设置域名
	if config.Domain != "" {
		netConfig.Domain = &libvirtxml.NetworkDomain{
			Name: config.Domain,
		}
	}

	// 设置 IP 配置
	for _, ipCfg := range config.IP {
		netIP := libvirtxml.NetworkIP{
			Address: ipCfg.Address,
			Netmask: ipCfg.Netmask,
		}

		if ipCfg.DHCP != nil {
			netIP.DHCP = &libvirtxml.NetworkDHCP{
				Ranges: []libvirtxml.NetworkDHCPRange{
					{
						Start: ipCfg.DHCP.Start,
						End:   ipCfg.DHCP.End,
					},
				},
			}

			// 添加静态主机
			for _, host := range ipCfg.DHCP.Hosts {
				netIP.DHCP.Hosts = append(netIP.DHCP.Hosts, libvirtxml.NetworkDHCPHost{
					MAC:  host.MAC,
					Name: host.Name,
					IP:   host.IP,
				})
			}
		}

		netConfig.IPs = append(netConfig.IPs, netIP)
	}

	return netConfig.Marshal()
}
